{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ae2fdf79-2253-4c7f-8412-f41f4ddde5a9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from glob import glob\n",
    "import os\n",
    "\n",
    "os.chdir('D:/AI全栈')\n",
    "\n",
    "text_lines = []\n",
    "        \n",
    "for file_path in glob(\"study_ai/api/mfd.md\", recursive=True):\n",
    "    with open(file_path, \"r\",encoding='utf-8') as file:\n",
    "        file_text = file.read()\n",
    "\n",
    "    text_lines += file_text.split(\"# \")\n",
    "   \n",
    "len(text_lines)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "6bb48baf-b678-4f4f-89de-868b420ba52d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n",
      "[-0.00993222  0.04682298 -0.03675228 -0.08068266 -0.02617284  0.0037349\n",
      "  0.00990155 -0.08762875 -0.01553682  0.05377049]\n",
      "[-0.00993222  0.04682298 -0.03675228 -0.08068266 -0.02617284  0.0037349\n",
      "  0.00990155 -0.08762875 -0.01553682  0.05377049]\n"
     ]
    }
   ],
   "source": [
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "\n",
    "test_embedding = embedding_model.encode_queries([\"登记机构\"])[0]\n",
    "embedding_dim = len(test_embedding)\n",
    "print(embedding_dim)\n",
    "print(test_embedding[:10])\n",
    "\n",
    "test_embedding_0 = embedding_model.encode_queries([\"不动产\"])[0]\n",
    "print(test_embedding_0[:10])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "4013599a-c1e4-4c64-b540-007b596fcd69",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n",
      "[-0.00993222  0.04682298 -0.03675228 -0.08068266 -0.02617284  0.0037349\n",
      "  0.00990155 -0.08762875 -0.01553682  0.05377049]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Creating mfd embeddings: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 78447.08it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'insert_count': 30, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], 'cost': 0}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pymilvus import MilvusClient\n",
    "from pymilvus import model as milvus_model\n",
    "from tqdm import tqdm\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"http://localhost:19530\")\n",
    "\n",
    "collection_name = \"my_rag_mfd_collection\"\n",
    "if milvus_client.has_collection(collection_name):\n",
    "    milvus_client.drop_collection(collection_name)\n",
    "\n",
    "test_embedding = embedding_model.encode_queries([\"登记机构\"])[0]\n",
    "embedding_dim = len(test_embedding)\n",
    "print(embedding_dim)\n",
    "print(test_embedding[:10])\n",
    "\n",
    "milvus_client.create_collection(\n",
    "    collection_name=collection_name,\n",
    "    dimension=embedding_dim,\n",
    "    metric_type=\"IP\",  # 内积距离\n",
    "    consistency_level=\"Strong\",  # 支持的值为 (`\"Strong\"`, `\"Session\"`, `\"Bounded\"`, `\"Eventually\"`)。更多详情请参见 https://milvus.io/docs/consistency.md#Consistency-Level。\n",
    ")\n",
    "\n",
    "data = []\n",
    "\n",
    "doc_embeddings = embedding_model.encode_documents(text_lines)\n",
    "\n",
    "for i, line in enumerate(tqdm(text_lines, desc=\"Creating mfd embeddings\")):\n",
    "    data.append({\"id\": i, \"vector\": doc_embeddings[i], \"text\": line})\n",
    "\n",
    "milvus_client.insert(collection_name=collection_name, data=data)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "4b53bcc4-4ef3-42a7-8d6c-6ad246245f39",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('第三章 合同的变更和转让\\n\\n**第五百四十八条** 当事人协商一致，可以变更合同。\\n\\n**第五百四十九条** 当事人对合同变更的内容约定不明确的，推定为未变更。\\n\\n**第五百五十条** 债权人可以将合同的权利全部或者部分转让给第三人，但是有下列情形之一的除外：\\n（一）根据合同性质不得转让；\\n（二）按照当事人约定不得转让；\\n（三）依照法律规定不得转让。\\n债权人转让权利的，应当通知债务人。未经通知，该转让对债务人不发生效力。\\n\\n**第五百五十一条** 债权人转让权利的，受让人取得与债权有关的从权利，但是该从权利专属于债权人自身的除外。\\n\\n**第五百五十二条** 债务人将合同的义务全部或者部分转让给第三人的，应当经债权人同意。\\n\\n**第五百五十三条** 债务人转让义务的，新债务人可以主张原债务人对债权人的抗辩。\\n新债务人承担债务的，应当承担与主债务有关的从债务，但是该从债务专属于原债务人自身的除外。\\n\\n**第五百五十四条** 当事人一方经对方同意，可以将自己在合同中的权利和义务一并转让给第三人。\\n\\n**第五百五十五条** 权利和义务一并转让的，适用债权转让、债务转让的有关规定。\\n\\n**第五百五十六条** 合同变更的，不影响当事人请求损害赔偿的权利。\\n\\n###', 0.6202715635299683), ('第五章 占有\\n\\n**第四百七十一条** 占有是指对物事实上的控制和支配。\\n\\n**第四百七十二条** 占有可以分为直接占有和间接占有。\\n直接占有是指直接对物进行控制和支配。\\n间接占有是指通过他人对物进行控制和支配。\\n\\n**第四百七十三条** 占有的取得和消灭，适用本法有关物权设立和消灭的规定。\\n\\n**第四百七十四条** 占有人合法占有动产的，善意取得人取得该动产所有权。\\n占有人非法占有动产的，善意取得人取得该动产所有权。\\n\\n**第四百七十五条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十六条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十七条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十八条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十九条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百八十条** 占有物被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n------\\n\\n##', 0.6135169267654419), ('第六节 地役权\\n\\n**第三百八十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n**第三百八十九条** 地役权合同一般包括下列条款：\\n（一）当事人的姓名或者名称和住所；\\n（二）供役地和需役地的位置；\\n（三）地役权的目的和期限；\\n（四）利用供役地的方式；\\n（五）报酬及其支付方式；\\n（六）争议解决方式。\\n\\n**第三百九十条** 设立地役权，当事人应当依照法律规定办理登记。\\n未经登记，不得对抗善意第三人。\\n\\n**第三百九十一条** 地役权人有权依照合同约定，利用供役地，以提高需役地的效益。\\n地役权人行使权利，不得损害供役地权利人的合法权益。\\n\\n**第三百九十二条** 供役地权利人应当按照约定，允许地役权人利用其土地。\\n供役地权利人不得妨碍地役权人行使权利。\\n\\n**第三百九十三条** 地役权期限届满或者地役权人放弃地役权的，地役权消灭。\\n地役权消灭的，登记机构应当依法办理注销登记。\\n\\n**第三百九十四条** 地役权人应当按照合同约定支付报酬。\\n地役权人应当按照合同约定，以合理的方式利用供役地。\\n\\n**第三百九十五条** 地役权不得单独转让。土地承包经营权、建设用地使用权、宅基地使用权等权利转让的，地役权一并转让。\\n地役权不得单独抵押。土地承包经营权、建设用地使用权、宅基地使用权等权利抵押的，地役权一并抵押。\\n\\n**第三百九十六条** 地役权存续期间，供役地权利人将供役地转让、出租或者抵押的，地役权不受影响。\\n\\n**第三百九十七条** 地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人有权请求赔偿损失。\\n地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人可以向供役地权利人请求损害赔偿。\\n\\n**第三百九十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n###', 0.6055376529693604)]\n"
     ]
    }
   ],
   "source": [
    "from pymilvus import MilvusClient\n",
    "import json\n",
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"http://localhost:19530\")\n",
    "\n",
    "collection_name = \"my_rag_mfd_collection\"\n",
    "\n",
    "question = \"登记机构\"\n",
    "\n",
    "search_res = milvus_client.search(\n",
    "    collection_name=collection_name,\n",
    "    data=embedding_model.encode_queries(\n",
    "        [question]\n",
    "    ),  # 将问题转换为嵌入向量\n",
    "    limit=3,  # 返回前3个结果\n",
    "    search_params={\"metric_type\": \"IP\", \"params\": {}},  # 内积距离\n",
    "    output_fields=[\"text\"],  # 返回 text 字段\n",
    ")\n",
    "\n",
    "retrieved_lines_with_distances = [\n",
    "    (res[\"entity\"][\"text\"], res[\"distance\"]) for res in search_res[0]\n",
    "]\n",
    "#print(json.dumps(retrieved_lines_with_distances[0], indent=4))\n",
    "print(retrieved_lines_with_distances)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3573ee8a-aa74-4530-85c2-47e8f9bc12a4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-----------------------------------------\n",
      "<translated>登记机构：根据法律规定办理登记的机构。根据上下文段落片段可以看出，第三百九十条中提到“设立地役权，当事人应当依照法律规定办理登记。”这个表述暗示了有一个相关的登记机构来办理地役权的注册工作。 </translated>\n",
      "\n",
      "-----------------------------------------\n",
      "总耗时：36962554200\n",
      "-----------------------------------------\n"
     ]
    }
   ],
   "source": [
    "from pymilvus import MilvusClient\n",
    "import ollama\n",
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"http://localhost:19530\")\n",
    "\n",
    "collection_name = \"my_rag_mfd_collection\"\n",
    "\n",
    "question = \"登记机构\"\n",
    "\n",
    "search_res = milvus_client.search(\n",
    "    collection_name=collection_name,\n",
    "    data=embedding_model.encode_queries(\n",
    "        [question]\n",
    "    ),  # 将问题转换为嵌入向量\n",
    "    limit=3,  # 返回前3个结果\n",
    "    search_params={\"metric_type\": \"IP\", \"params\": {}},  # 内积距离\n",
    "    output_fields=[\"text\"],  # 返回 text 字段\n",
    ")\n",
    "\n",
    "retrieved_lines_with_distances = [\n",
    "    (res[\"entity\"][\"text\"], res[\"distance\"]) for res in search_res[0]\n",
    "]\n",
    "\n",
    "\n",
    "context = \"\\n\".join(\n",
    "    [line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]\n",
    ")\n",
    "\n",
    "print(\"------------------------------\\n\")\n",
    "print(f\"{context}\\n\")\n",
    "\n",
    "SYSTEM_PROMPT = \"\"\"\n",
    "Human: 你是一个 AI 助手。你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\"\n",
    "\n",
    "USER_PROMPT = f\"\"\"\n",
    "Human: 你是一个 AI 助手。你能够从提供的上下文段落片段中找到问题的答案。\n",
    "请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。最后追加原始回答的中文翻译，并用 <translated>和</translated> 标签标注。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question}\n",
    "</question>\n",
    "<translated>\n",
    "</translated>\n",
    "\"\"\"\n",
    "\n",
    "stream = ollama.chat(\n",
    "    stream=True,\n",
    "    model='llama3.2:latest', # 修改大模型名称1\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
    "        {\"role\": \"user\", \"content\": USER_PROMPT}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print('-----------------------------------------')\n",
    "for chunk in stream:\n",
    "    if not chunk['done']:\n",
    "        print(chunk['message']['content'], end=\"\", flush=True)\n",
    "    else:\n",
    "        print('\\n')\n",
    "        print('-----------------------------------------')\n",
    "        print(f'总耗时：{chunk['total_duration']}')\n",
    "        print('-----------------------------------------')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "989f464b-76c8-428c-bbfa-cc488cb79101",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-----------------------------------------\n",
      "<translated>根据合同法的规定，不动产包括以下几个方面的权利：占有权、用地权、用 build 材料权和其他不动产权。这些权利可以分为直接占有和间接占有，后者指通过他人对物进行控制和支配。</translated>\n",
      "\n",
      "-----------------------------------------\n",
      "总耗时：36966774600\n",
      "-----------------------------------------\n"
     ]
    }
   ],
   "source": [
    "from pymilvus import MilvusClient\n",
    "import ollama\n",
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"http://localhost:19530\")\n",
    "\n",
    "collection_name = \"my_rag_mfd_collection\"\n",
    "\n",
    "question = \"不动产有什么权利\"\n",
    "\n",
    "search_res = milvus_client.search(\n",
    "    collection_name=collection_name,\n",
    "    data=embedding_model.encode_queries(\n",
    "        [question]\n",
    "    ),  # 将问题转换为嵌入向量\n",
    "    limit=3,  # 返回前3个结果\n",
    "    search_params={\"metric_type\": \"IP\", \"params\": {}},  # 内积距离\n",
    "    output_fields=[\"text\"],  # 返回 text 字段\n",
    ")\n",
    "\n",
    "retrieved_lines_with_distances = [\n",
    "    (res[\"entity\"][\"text\"], res[\"distance\"]) for res in search_res[0]\n",
    "]\n",
    "\n",
    "\n",
    "context = \"\\n\".join(\n",
    "    [line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]\n",
    ")\n",
    "\n",
    "SYSTEM_PROMPT = \"\"\"\n",
    "Human: 你是一个 AI 助手。你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\"\n",
    "\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。最后追加原始回答的中文翻译，并用 <translated>和</translated> 标签标注。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question}\n",
    "</question>\n",
    "<translated>\n",
    "</translated>\n",
    "\"\"\"\n",
    "\n",
    "stream = ollama.chat(\n",
    "    stream=True,\n",
    "    model='llama3.2:latest', # 修改大模型名称1\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
    "        {\"role\": \"user\", \"content\": USER_PROMPT}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print('-----------------------------------------')\n",
    "for chunk in stream:\n",
    "    if not chunk['done']:\n",
    "        print(chunk['message']['content'], end=\"\", flush=True)\n",
    "    else:\n",
    "        print('\\n')\n",
    "        print('-----------------------------------------')\n",
    "        print(f'总耗时：{chunk['total_duration']}')\n",
    "        print('-----------------------------------------')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ae18f0d-59e8-434d-8059-59719aa1d9b2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
